#!/usr/bin/python
# -*- coding: utf-8 -*-
# 

import maya.cmds as mc

import LZ_public_command.LZ_general_command as LZ_general_command
reload(LZ_general_command)

import LZ_public_command.LZ_rivet as LZ_rivet
reload(LZ_rivet)

import LZ_public_command.LZ_Attribute as LZ_Attribute
reload(LZ_Attribute)

import LZ_public_command.LZ_sdk_command as LZ_sdk_command
reload(LZ_sdk_command)

import LZ_public_command.LZ_controllar_command as LZ_controllar_command
reload(LZ_controllar_command)

class create_muscle_simulation( LZ_general_command.general_command,
                                LZ_rivet.LZ_rivetClass,
                                LZ_Attribute.LZ_attribute,
                                LZ_sdk_command.LZ_sdk_command,
                                LZ_controllar_command.LZ_controllar_command
                                ):
    def __init__(self):
        pass
        
    def createTemple_muscle(self):
    
        pass
        
    def create_muscle_simulation(self , prefix = '' , startLoc = '' , endloc = '' ,spans = 3 ):
        
        donotTouch_grp = prefix + '_donottouch_grp'
        parentRoot_grp = prefix + '_parentRoot_grp'
        for gp in [ donotTouch_grp , parentRoot_grp ]:
            if mc.objExists( gp ) == 0 :
                mc.group(em=True , n = gp )
        
        
        grp_squzze = [ '_zero' ,'_con' ,'_global','_sdk','_ac'] 
        
        
        startPosition = mc.xform( startLoc , q=True , t=True ,ws =True )
        endPosition = mc.xform( endloc , q=True , t=True ,ws =True )
        
        if startPosition == endPosition:
        
            print(' can not be zero the distance between startloc and endloc ')
        
        else:
            curveSpine = prefix + '_muscle_curve'
            curveinfo = mc.curve( d = 1 , p = ( (startPosition[0], startPosition[1] , startPosition[2]  ),( endPosition[0] , endPosition[1] , endPosition[2] ) ), k = (0 ,1) , n = curveSpine)
            mc.parent( curveSpine , donotTouch_grp )
            mc.rebuildCurve ( curveinfo  , ch = False ,  rpo =  1 , rt =  0, end  = 1 , kr = 0 ,  kcp = 0 , kep = 1 , kt = 0 , s = 2 , d = 3 , tol = 0.01 )
            
            
            stratJnt = prefix + '_muscle_startJnt'
            endJnt = prefix + '_muscle_endJnt'
            
            self.createTransformer( locName = stratJnt , position = startPosition ,rotation = ( 0,0,0) ,type = 'joint',LocPosion = (0,0,0))
            self.createTransformer( locName = endJnt , position = endPosition ,rotation = ( 0,0,0) ,type = 'joint',LocPosion = (0,0,0))
            
            for sufix in grp_squzze :
            
                self.makeZeroGrpTwo( OrgObj = [stratJnt , endJnt ] , sufname = sufix,cenObj='',Mode=0,type = 'group',ro =True )
            
            
            ##  fix rotation axis        
            constraintnode = mc.aimConstraint(  stratJnt , str(endJnt)+'_zero'  , offset =( 0, 0, 0) , weight = 1 , aimVector = ( 1, 0 ,0 ), upVector = ( 0 ,1 ,0),  worldUpType = "vector", worldUpVector = (0 ,1 ,0 ) )
            mc.delete( constraintnode )
            
            constraintnode = mc.aimConstraint(  endJnt , str(stratJnt)+'_zero'  , offset =( 0, 0, 0) , weight = 1 , aimVector = ( -1, 0 ,0 ), upVector = ( 0 ,1 ,0),  worldUpType = "vector", worldUpVector = (0 ,1 ,0 ) )
            mc.delete( constraintnode )
            ###------------------------------------------
            
            ##  - add skinCluster  to curve 
            
            skin_node = mc.skinCluster( stratJnt ,endJnt , curveinfo)
            
            
            mc.skinPercent( skin_node[0] ,str( curveSpine )+'.cv[3]', transformValue=[(stratJnt, 0.15), (endJnt, 0.85)] ) 
            mc.skinPercent( skin_node[0] ,str( curveSpine )+'.cv[1]', transformValue=[(stratJnt, 0.85), (endJnt, 0.15)] ) 
            
            
            
            startPosition
            endPosition
            disPosition =  ((startPosition[0] - endPosition[0] )**2 + ( startPosition[1] - endPosition[1] )**2 +(startPosition[2] - endPosition[2] )**2)**0.5
            
            
            loftCurve_grp = prefix + '_loft_curve_grp'
            if mc.objExists(loftCurve_grp) == 0 :
                mc.group( em =True ,n =loftCurve_grp )
                mc.parent( loftCurve_grp , donotTouch_grp )
            startCurve = prefix + '_muscle_01_curve'
            endCurve = prefix + '_muscle_0'+ str(spans) +  '_curve'
            
            ###
            mc.circle( ch = False ,  o = True  , nr = ( 1 ,0 ,0 ), r = disPosition/8 ,n = startCurve )
            mc.parent( startCurve , stratJnt )
            for attr in ['.tx','.ty','.tz','.rx','.ry','.rz']:
                mc.setAttr( str(startCurve) + str(attr) , 0 )
            mc.parent( startCurve ,loftCurve_grp )
            
            ###
            mc.circle( ch = False ,  o = True  , nr = ( 1 ,0 ,0 ), r = disPosition/8 ,n = endCurve )
            mc.parent( endCurve , endJnt )
            for attr in ['.tx','.ty','.tz','.rx','.ry','.rz']:
                mc.setAttr( str(endCurve) + str(attr) , 0 ) 
                
            mc.parent( endCurve ,loftCurve_grp )
            
            for sufix in grp_squzze :
            
                self.makeZeroGrpTwo( OrgObj = [startCurve , endCurve ] , sufname = sufix,cenObj='',Mode=0,type = 'group',ro =True )
                
                
            mc.orientConstraint(  stratJnt , str(startCurve)+'_con'  )
            mc.orientConstraint(  endJnt , str(endCurve)+'_con'  )
            self.LZ_rivet( motherType = 'curve',inputObj = curveSpine ,rivetObj = [ str(startCurve)+'_con' ,str(endCurve)+'_con'],IsRotate = 0)
            
            ######
            midCurve = prefix + '_muscle_0'+ str((spans+1)/2) +  '_curve'
            mc.circle( ch = False ,  o = True  , nr = ( 1 ,0 ,0 ), r = disPosition/2.5 ,n = midCurve )
            
            
            cons_node = mc.pointConstraint( stratJnt , endJnt , midCurve ,mo =False )
            mc.delete(cons_node)
            
            cons_node = mc.orientConstraint( stratJnt , endJnt , midCurve , mo =False )
            mc.delete(cons_node)
            
            mc.parent( midCurve ,loftCurve_grp )
            
            
            for sufix in grp_squzze :
            
                self.makeZeroGrpTwo( OrgObj = [midCurve ] , sufname = sufix,cenObj='',Mode=0,type = 'group',ro =True )
                
            mc.orientConstraint( stratJnt , endJnt , str(midCurve)+'_con' ,mo =False )
            self.LZ_rivet( motherType = 'curve',inputObj = curveSpine ,rivetObj = [ str(midCurve)+'_con' ],IsRotate = 0)
            
            
            
            nurbsSurface = prefix + '_muscle_surface'
            if spans == 3 :
                nurbs = mc.loft( startCurve , midCurve, endCurve , ch = True ,   rn=True, ar=True )
                
            elif spans == 5:
                
                ######
                startMidCurve = prefix + '_muscle_02'+ '_curve'
                mc.circle( ch = False ,  o = True  , nr = ( 1 ,0 ,0 ), r = disPosition/3 ,n = startMidCurve )
                
                
                cons_node = mc.pointConstraint( stratJnt , midCurve , startMidCurve ,mo =False )
                mc.delete(cons_node)
                
                cons_node = mc.orientConstraint( stratJnt , midCurve , startMidCurve , mo =False )
                mc.delete(cons_node)
                
                mc.parent( startMidCurve ,loftCurve_grp )
                
                
                for sufix in grp_squzze :
                
                    self.makeZeroGrpTwo( OrgObj = [startMidCurve ] , sufname = sufix,cenObj='',Mode=0,type = 'group',ro =True )
                    
                mc.orientConstraint( stratJnt , midCurve , str(startMidCurve)+'_con' ,mo =False )
                self.LZ_rivet( motherType = 'curve',inputObj = curveSpine ,rivetObj = [ str(startMidCurve)+'_con' ],IsRotate = 0 )
                
                ######
                endMidCurve = prefix + '_muscle_04'+ '_curve'
                mc.circle( ch = False ,  o = True  , nr = ( 1 ,0 ,0 ), r = disPosition/3 ,n = endMidCurve )
                
                
                cons_node = mc.pointConstraint( endJnt , midCurve , endMidCurve ,mo =False )
                mc.delete(cons_node)
                
                cons_node = mc.orientConstraint( endJnt , midCurve , endMidCurve , mo =False )
                mc.delete(cons_node)
                
                mc.parent( endMidCurve ,loftCurve_grp )
                
                
                for sufix in grp_squzze:
                
                    self.makeZeroGrpTwo( OrgObj = [endMidCurve ] , sufname = sufix,cenObj='',Mode=0,type = 'group',ro =True )
                    
                mc.orientConstraint( endJnt , midCurve , str(endMidCurve)+'_con' ,mo =False )
                self.LZ_rivet( motherType = 'curve',inputObj = curveSpine ,rivetObj = [ str(endMidCurve)+'_con' ],IsRotate = 0 )
                
                
                nurbs = mc.loft( startCurve , startMidCurve , midCurve,endMidCurve , endCurve , ch = True ,   rn=True, ar=True )
                
                
            mc.rename(  nurbs[0] , nurbsSurface )
            mc.parent( nurbsSurface , donotTouch_grp )
            ##=================================================================
            #----------------------------------------------------
            # ----------  create distance node -------------------------
            
            #startRotation = mc.xform( startLoc , q=True , t=True ,ws =True )
            #endRotation = mc.xform( endloc , q=True , t=True ,ws =True )
            addAttributes  = [ 'rest_len' ,'default_len' ,'current_len' , 'stretch_len' ,'squash_len', 'stretch_act' ,'squash_act','times','current_data'    ]
            bridgeStretch = prefix + '_stretch_bridge'
            if mc.objExists(bridgeStretch) == 0:
                mc.group(em =True , n = bridgeStretch )
                mc.parent( bridgeStretch , parentRoot_grp )
            
            for aas in addAttributes:
                self.addAttrs( objname=[ bridgeStretch ],attrname= aas ,dv=0,key=1)
            
            #---
            state_startDis_loc =  prefix + '_state_start_loc'
            state_endDis_loc=  prefix + '_state_end_loc'
            
            self.createTransformer( locName = state_startDis_loc , position = startPosition ,rotation = ( 0,0,0) ,type = 'locator',LocPosion = (0,0,0))
            self.createTransformer( locName = state_endDis_loc , position = endPosition ,rotation = ( 0,0,0) ,type = 'locator',LocPosion = (0,0,0) )
            
            mc.parent( state_startDis_loc,state_endDis_loc , parentRoot_grp )
            
            statedistanceBetween = prefix + '_state_distanceBetween'
            mc.createNode('distanceBetween' , n = statedistanceBetween )
            
            locator_startShape = mc.listRelatives( state_startDis_loc , s=True  )
            locator_endShape = mc.listRelatives( state_endDis_loc , s=True  )
            
            mc.connectAttr( str(locator_startShape[0]) + '.worldPosition[0]' ,  str(statedistanceBetween) + '.point1'  )
            mc.connectAttr( str(locator_endShape[0]) + '.worldPosition[0]' ,  str(statedistanceBetween) + '.point2'  )
            
            mc.connectAttr( str( statedistanceBetween ) + '.distance' ,  str(bridgeStretch) + '.' + str(addAttributes[0]) )
            
            defaultLen = mc.getAttr(str( statedistanceBetween ) + '.distance')
            mc.setAttr(  str(bridgeStretch) + '.' + str(addAttributes[1]) , defaultLen )
            
            mc.setAttr(  str(bridgeStretch) + '.' + str(addAttributes[3]) , defaultLen*0.75 )
            mc.setAttr(  str(bridgeStretch) + '.' + str(addAttributes[4]) , defaultLen*1.5 )
            #---------
            dynamic_startDis_loc =  prefix + '_dynamic_start_loc'
            dynamic_endDis_loc=  prefix + '_dynamic_end_loc'
            
            self.createTransformer( locName = dynamic_startDis_loc , position = startPosition ,rotation = ( 0,0,0) ,type = 'locator',LocPosion = (0,0,0))
            self.createTransformer( locName = dynamic_endDis_loc , position = endPosition ,rotation = ( 0,0,0) ,type = 'locator',LocPosion = (0,0,0) )
            
            dynamicdistanceBetween = prefix + '_dynamic_distanceBetween'
            mc.createNode('distanceBetween' , n = dynamicdistanceBetween )
            
            locator_startShape = mc.listRelatives( dynamic_startDis_loc , s=True  )
            locator_endShape = mc.listRelatives( dynamic_endDis_loc , s=True  )
            
            mc.connectAttr( str(locator_startShape[0]) + '.worldPosition[0]' ,  str(dynamicdistanceBetween) + '.point1'  )
            mc.connectAttr( str(locator_endShape[0]) + '.worldPosition[0]' ,  str(dynamicdistanceBetween) + '.point2'  )
            
            mc.connectAttr( str( dynamicdistanceBetween ) + '.distance' ,  str(bridgeStretch) + '.' + str(addAttributes[2]) )
            #---------
            global_md =  prefix + '_global_md'
            stretch_md =  prefix + '_stretch_md'
            squash_md =  prefix + '_squash_md'
            for mdnode in [ global_md, stretch_md , squash_md ]:
                if mc.objExists(mdnode) == 0:
                    mc.createNode( 'multiplyDivide' , n = mdnode  )
            
            
            
            mc.connectAttr(  str(bridgeStretch) + '.' + str(addAttributes[0]) , str(global_md)+'.input1X' )
            mc.connectAttr(  str(bridgeStretch) + '.' + str(addAttributes[1]) , str(global_md)+'.input2X' )
            mc.setAttr( str(global_md)+'.operation' , 2  )
            
            mc.connectAttr( str(global_md)+'.outputX' , str(stretch_md)+'.input1X' )
            mc.connectAttr( str(bridgeStretch) + '.' + str(addAttributes[3]) , str(stretch_md)+'.input2X' )
            mc.connectAttr( str(stretch_md)+'.outputX' , str(bridgeStretch) + '.' + str(addAttributes[5])  )
            
            mc.connectAttr( str(global_md)+'.outputX' , str(squash_md)+'.input1X' )
            mc.connectAttr( str(bridgeStretch) + '.' + str(addAttributes[4]) , str(squash_md)+'.input2X' )
            mc.connectAttr( str(squash_md)+'.outputX' , str(bridgeStretch) + '.' + str(addAttributes[6])  )
            
            mc.parent( dynamic_startDis_loc , stratJnt )
            mc.parent( dynamic_endDis_loc , endJnt )
            
            curveZeroGrp  = mc.listRelatives( loftCurve_grp , c =True ,ad = False )
            
            for czg in curveZeroGrp:
                for att in ['.sx','.sy','.sz']:
                
                    gloabalGrp = str(czg).replace( '_zero' , '_global' )
                    mc.connectAttr( str(global_md)+'.outputX' , str(gloabalGrp)+str(att)  )
                    
                    
                    
            ##-------------------
            #stretch_diff_pma = prefix + '_stretch_diff_pma'
            stretch_times_md = prefix + '_stretch_times_md'
            
            #squash_diff_pma = prefix + '_squash_diff_pma'
            #squash_times_md = prefix + '_squash_times_md'
            
            
            #mc.createNode( 'plusMinusAverage' , n = stretch_diff_pma )
            mc.createNode( 'multiplyDivide' , n = stretch_times_md )
            #mc.createNode( 'plusMinusAverage' , n = squash_diff_pma )
            #mc.createNode( 'multiplyDivide' , n = squash_times_md )
            
            
            
            #mc.connectAttr(  str(bridgeStretch) + '.' + str(addAttributes[2])  , str( stretch_diff_pma )+'.input1D[0]'  )
            #mc.connectAttr(  str(bridgeStretch) + '.' + str(addAttributes[0])  , str( stretch_diff_pma )+'.input1D[1]'  )
            #mc.setAttr( str( stretch_diff_pma )+'.operation' , 2  )
            #
            
            mc.connectAttr(  str(bridgeStretch) + '.' + str(addAttributes[2])  , str( stretch_times_md )+'.input1X'  )
            mc.connectAttr(  str(bridgeStretch) + '.' + str(addAttributes[0])  , str( stretch_times_md )+'.input2X'  )
            mc.setAttr( str(stretch_times_md)+'.operation' , 2 )
            mc.connectAttr(  str( stretch_times_md )+'.outputX',  str(bridgeStretch) + '.' + str(addAttributes[7])  )
            #@current_len_value = mc.getAttr( str(bridgeStretch) + '.' + str(addAttributes[2])  )
            #@squash_len_value = mc.getAttr( str(bridgeStretch) + '.' + str(addAttributes[4])  )
            #@stretch_len_value = mc.getAttr( str(bridgeStretch) + '.' + str(addAttributes[3])  )
            #@
            
            self.LZ_serDrivenKey_02( driverAttr = str(bridgeStretch) + '.' + str(addAttributes[7]) , drivenAttr = str(bridgeStretch) + '.' + str(addAttributes[8])  ,driverV = [0.75,1,1.5] , drivenV = [ 0 , 1,2 ] ,inType = 'linear' ,outType = 'linear' , preV = 'constant', poiV = 'constant')
            
            
            ###================================================================
            #-----------------------------------------------------------------
            
            
            
            
            
            
            
            ##=================================================================
            #----------------------------------------------------
            
            allChilddren = mc.listRelatives( loftCurve_grp , c =True ,ad =True )
            allCurve = []
            
            for ac in allChilddren:
                if mc.nodeType(ac) == 'nurbsCurve':
                    #print(ac)
                    curveBase = mc.listRelatives( ac , p=True ,c=False )[0]
                    allCurve.append(curveBase)
            mount = len(allCurve)
            for acu in allCurve:
                rest_curve = str(acu) + '_rest'
                stretchCurve = str(acu) + '_stretch'
                squashCurve = str(acu) + '_squash'
                
                mc.duplicate( acu , n = rest_curve )
                mc.duplicate( acu , n = stretchCurve )
                mc.duplicate( acu , n = squashCurve )
                
                if '_01_' in acu or '_0'+str(mount)+'_' in acu :
                    pass
                    
                else:
                    self.scaleCurveHull( squashCurve,1.5,1.5,1.5)
                    self.scaleCurveHull( stretchCurve,0.75,0.75,0.75)
                
                
                for cur in [ rest_curve , stretchCurve , squashCurve ]:
                    mc.setAttr(str(cur)+'.v' , 0 )
                
                blendNode = mc.blendShape( rest_curve,stretchCurve , squashCurve , acu )
            
                self.LZ_serDrivenKey_02( driverAttr = str(bridgeStretch) + '.' + str(addAttributes[8]) , drivenAttr = str(blendNode[0]) + '.' + str(rest_curve)  ,driverV = [0,1,2] , drivenV = [ 0 , 1 , 0 ] ,inType = 'linear' ,outType = 'linear' , preV = 'constant', poiV = 'constant')
            
                self.LZ_serDrivenKey_02( driverAttr = str(bridgeStretch) + '.' + str(addAttributes[8]) , drivenAttr = str(blendNode[0]) + '.' + str(stretchCurve)  ,driverV = [ 1,2] , drivenV = [ 0 , 1 ] ,inType = 'linear' ,outType = 'linear' , preV = 'constant', poiV = 'constant')
            
                self.LZ_serDrivenKey_02( driverAttr = str(bridgeStretch) + '.' + str(addAttributes[8]) , drivenAttr = str(blendNode[0]) + '.' + str(squashCurve)  ,driverV = [ 0,1] , drivenV = [ 1 , 0 ] ,inType = 'linear' ,outType = 'linear' , preV = 'constant', poiV = 'constant')
            
                self.makeObjReferenced(  obj = acu )
                ###-------------------------------------------
                
                
                sdkGrp = str(acu)+ '_sdk'
                resetGrp = str(acu)+ '_rest_ac'
                stretchGrp = str(acu)+ '_stretch_ac'
                squashGrp = str(acu)+ '_squash_ac'
                
                for grp in [resetGrp , stretchGrp , squashGrp ]:
                    mc.group( em=True, n= grp)
                    parentGrp = mc.listRelatives( sdkGrp ,p=True ,c=False)
                    
                    mc.parent( grp ,parentGrp[0])
                    self.resetAllAttrs( ctrl_obj = grp )
                    
            
                    mc.setAttr( str(grp) + '.v' , 0 )
                    self.creatControls_command( type = 2 , curName=grp , add=True)
            
                constraintNode = str(grp) + '_parentConstrant'
                scaleconstraintNode = str(grp) + '_parentConstrant'
                constraint = mc.parentConstraint( resetGrp , stretchGrp , squashGrp , sdkGrp ,n = constraintNode )
                scaleconstraint = mc.scaleConstraint( resetGrp , stretchGrp , squashGrp , sdkGrp ,n = scaleconstraintNode )
                
                
                for con in [ constraint , scaleconstraint ]:
                
                    self.LZ_serDrivenKey_02( driverAttr = str(bridgeStretch) + '.' + str(addAttributes[8]) , drivenAttr = str(con[0]) + '.' + str(resetGrp) +'W0' ,driverV = [0,1,2] , drivenV = [ 0 , 1 , 0 ] ,inType = 'linear' ,outType = 'linear' , preV = 'constant', poiV = 'constant')
                    self.LZ_serDrivenKey_02( driverAttr = str(bridgeStretch) + '.' + str(addAttributes[8]) , drivenAttr = str(con[0]) + '.' + str(stretchGrp) +'W1' ,driverV = [ 1,2] , drivenV = [ 0 , 1 ] ,inType = 'linear' ,outType = 'linear' , preV = 'constant', poiV = 'constant')
                    self.LZ_serDrivenKey_02( driverAttr = str(bridgeStretch) + '.' + str(addAttributes[8]) , drivenAttr = str(con[0]) + '.' + str(squashGrp) +'W2' ,driverV = [ 0,1] , drivenV = [ 1 , 0 ] ,inType = 'linear' ,outType = 'linear' , preV = 'constant', poiV = 'constant')
                
                
            
            
            
            
        